package com.jdrx.sw.sewage.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jdrx.platform.commons.rest.exception.BizException;
import com.jdrx.sw.sewage.beans.dto.*;
import com.jdrx.sw.sewage.beans.entity.AlarmSetPO;
import com.jdrx.sw.sewage.beans.entity.DeviceTimeDataPO;
import com.jdrx.sw.sewage.beans.entity.StationReportAnalysisPO;
import com.jdrx.sw.sewage.beans.vo.*;
import com.jdrx.sw.sewage.common.enums.EAlarmLevel;
import com.jdrx.sw.sewage.common.enums.InOutType;
import com.jdrx.sw.sewage.common.util.LocalDateTimeUtils;
import com.jdrx.sw.sewage.common.util.NumberUtil;
import com.jdrx.sw.sewage.dao.*;
import com.jdrx.sw.sewage.service.base.BaseServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.util.Asserts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.jdrx.sw.sewage.common.constant.Constant.*;

@Service
public class StationReportAnalysisServiceImpl extends BaseServiceImpl {

    public static final Logger logger = LoggerFactory.getLogger(StationReportServiceImpl.class);

    @Autowired
    private DeviceTimeDataDAO deviceTimeDataDao;
    @Autowired
    private StationReportAnalysisDAO stationReportAnalysisDAO;
    @Autowired
    private AlarmSetDAO alarmSetDAO;
    @Autowired
    private StationWaterQualityDAO stationWaterQualityDAO;
    @Autowired
    private GatherDevPointDAO gatherDevPointDAO;

    public List<DeviceTimeDataPO> selectRealTimeLastPacksByParams(Map<String, Object> params) throws BizException {
        Asserts.notNull(params, "数据过滤参数");
        try {
            return deviceTimeDataDao.selectRealTimeLastPacksByParams(params);
        } catch (Exception e) {
            logger.error("数据过滤失败", e);
            throw new BizException("数据过滤失败");
        }
    }

    public void batchInsertHistory(List<StationReportAnalysisPO> lists, String dataNode) throws BizException {
        Map<String, Object> params = Maps.newHashMap();
        if (CollectionUtils.isEmpty(lists)) return;

        params.put("list", lists);
        params.put("dataNode", dataNode);
        int count = stationReportAnalysisDAO.batchInsertHistory(params);
    }

    public List<WaterYieldVO> selectWaterYield(DnbThanSurfaceDTO waterYieldQueryDTO) {
        return stationReportAnalysisDAO.selectWaterYield(waterYieldQueryDTO);
    }

    public Map<LocalDateTime, List<ReportAnalysisVO>> selectInAndOutWaterYield(WaterYieldQueryDTO waterYieldQueryDTO) {
        waterYieldQueryDTO.setInOrOut(InOutType.IN_OUT.getKey());
        List<ReportAnalysisVO> reportAnalysisVOs = stationReportAnalysisDAO.selectInAndOutWaterYield(waterYieldQueryDTO);
        if (null == reportAnalysisVOs || reportAnalysisVOs.size() <= 0) return new HashMap<>();
//        Map<Integer, List<ReportAnalysisVO>> groupBy = reportAnalysisVOs.stream().collect(Collectors.groupingBy(ReportAnalysisVO::getInOrOut));//串行
        Map<LocalDateTime, List<ReportAnalysisVO>> groupBy = reportAnalysisVOs.stream().collect(Collectors.groupingByConcurrent(ReportAnalysisVO::getCreateTime));//并行
        return groupBy;
    }

    public List<StationReportAnalysisPO> selectWaterQuality(WaterQualityQueryDTO waterQualityQueryDTO) {
        List<StationReportAnalysisPO> reportAnalysisVOs = stationReportAnalysisDAO.selectWaterQuality(waterQualityQueryDTO);
        return reportAnalysisVOs;
    }

    public List<ReportAnalysisVO> selectDnbSurface(WaterYieldQueryDTO waterYieldQueryDTO) {
        return stationReportAnalysisDAO.selectDnbSurface(waterYieldQueryDTO);
    }

    public List<DnbSurfaceVO> selectDnbThanSurface(DnbThanSurfaceDTO dnbThanSurfaceDTO) {
        List<WaterYieldVO> dnbSurfaceList = stationReportAnalysisDAO.selectTotalDnbSurface(dnbThanSurfaceDTO);
        List<DnbSurfaceVO> list = Lists.newArrayList();
        if (null == dnbSurfaceList || dnbSurfaceList.size() <= 0) return list;

        dnbThanSurfaceDTO.setInOrOut(InOutType.OUT.getKey());
        List<WaterYieldVO> waterYieldList = stationReportAnalysisDAO.selectTotalWaterYield(dnbThanSurfaceDTO);
        //单位时间内的能耗（千瓦时）/单位时间内的水量
        dnbSurfaceList.forEach(dnbSurface -> {
            waterYieldList.forEach(waterYield -> {
                if (dnbSurface.getStationId() == waterYield.getStationId()) {
                    DnbSurfaceVO dnbSurfaceVO = new DnbSurfaceVO();
                    dnbSurfaceVO.setStationId(waterYield.getStationId());
                    dnbSurfaceVO.setStationName(waterYield.getStationName());
                    dnbSurfaceVO.setDnbSurface(dnbSurface.getTotalYield() / waterYield.getTotalYield());
                    list.add(dnbSurfaceVO);
                }
            });
        });
        return list;
    }

    public Map<Integer, List<ReportAnalysisVO>> selectWaterCodQuality(WaterCodQualityQueryDTO waterCodQualityQueryDTO) {
        List<ReportAnalysisVO> reportAnalysisVOs = stationReportAnalysisDAO.selectWaterCodQuality(waterCodQualityQueryDTO);

        if (null == reportAnalysisVOs || reportAnalysisVOs.size() <= 0) return new HashMap<>();
        Map<Integer, List<ReportAnalysisVO>> groupBy = reportAnalysisVOs.stream().collect(Collectors.groupingByConcurrent(ReportAnalysisVO::getInOrOut));
        return groupBy;
    }

    public List<DnbSurfaceVO> selectDnbThanSurfaceAnalysis(DnbSurfaceQueryDTO dto) {
        return stationReportAnalysisDAO.selectDnbThanSurfaceAnalysis(dto);
    }

    /*public Map<Integer, List<ReportAnalysisVO>> waterQualityMonitor(WaterQualityMonitorDTO dto) {
        List<ReportAnalysisVO> reportAnalysisVOs = stationReportAnalysisDAO.waterQualityMonitor(dto);
        if (null == reportAnalysisVOs || reportAnalysisVOs.size() <= 0) return new HashMap<>();
        Map<Integer, List<ReportAnalysisVO>> groupBy = reportAnalysisVOs.stream().collect(Collectors.groupingByConcurrent(ReportAnalysisVO::getType));
        return groupBy;
    }*/

    public Map<String, Map<Integer, List<WaterQualityVO>>> waterQualityMonitor(WaterQualityMonitorDTO dto) {
        Map<String, Map<Integer, List<WaterQualityVO>>> map = Maps.newHashMap();
        List<WaterQualityVO> cod = stationWaterQualityDAO.waterQualityMonitor(dto.getStationId(), COD);
        List<WaterQualityVO> nh3n = stationWaterQualityDAO.waterQualityMonitor(dto.getStationId(), NH3N);
        List<WaterQualityVO> tn = stationWaterQualityDAO.waterQualityMonitor(dto.getStationId(), TN);
        List<WaterQualityVO> ph = stationWaterQualityDAO.waterQualityMonitor(dto.getStationId(), PH);
        List<WaterQualityVO> tp = stationWaterQualityDAO.waterQualityMonitor(dto.getStationId(), TP);
        List<WaterQualityVO> ss = stationWaterQualityDAO.waterQualityMonitor(dto.getStationId(), SS);
        List<WaterQualityVO> wd = stationWaterQualityDAO.waterQualityMonitor(dto.getStationId(), WD);

        if (null == cod || cod.size() <= 0) map.put("COD", Maps.newHashMap());
        else map.put("COD", cod.stream().collect(Collectors.groupingByConcurrent(WaterQualityVO::getInOut)));

        if (null == cod || cod.size() <= 0) map.put("氨氮", Maps.newHashMap());
        else map.put("氨氮", nh3n.stream().collect(Collectors.groupingByConcurrent(WaterQualityVO::getInOut)));

        if (null == cod || cod.size() <= 0) map.put("TN", Maps.newHashMap());
        else map.put("TN", tn.stream().collect(Collectors.groupingByConcurrent(WaterQualityVO::getInOut)));

        if (null == cod || cod.size() <= 0) map.put("PH", Maps.newHashMap());
        else map.put("PH", ph.stream().collect(Collectors.groupingByConcurrent(WaterQualityVO::getInOut)));

        if (null == cod || cod.size() <= 0) map.put("TP", Maps.newHashMap());
        else map.put("TP", tp.stream().collect(Collectors.groupingByConcurrent(WaterQualityVO::getInOut)));

        if (null == cod || cod.size() <= 0) map.put("SS", Maps.newHashMap());
        else map.put("SS", ss.stream().collect(Collectors.groupingByConcurrent(WaterQualityVO::getInOut)));

        if (null == cod || cod.size() <= 0) map.put("温度", Maps.newHashMap());
        else map.put("温度", wd.stream().collect(Collectors.groupingByConcurrent(WaterQualityVO::getInOut)));

        return map;
    }

    public Map<Integer, List> dnbStatistics(DnbStatisticsDTO dto) {
        String time = null;
        if (2 == dto.getReportType()) time = LocalDateTimeUtils.localDateCURRMONTHToString(new Date());
        if (3 == dto.getReportType()) time = LocalDateTimeUtils.localDateCURRYoString(new Date());
        List<ReportAnalysisVO> dnbValue = stationReportAnalysisDAO.selectDnbStatisticsSurface(dto.getStationId(), dto.getReportType(), time);
        List<DnbSurfaceVO> dnbThan = stationReportAnalysisDAO.selectDnbStatisticsThan(dto.getStationId(), dto.getReportType(), time);
        HashMap map = Maps.newHashMap();
        map.put("dnbValue", dnbValue);
        map.put("dnbThan", dnbThan);
        return map;
    }

    public List<ReportAnalysisVO> handleWater(DnbStatisticsDTO dto) {
        List<ReportAnalysisVO> value = stationReportAnalysisDAO.handleWater(dto.getStationId(), dto.getReportType());
        return value;
    }

    public Map<String, Double> operationAnalysis(OperationAnalysisDTO dto) {
        List<Double> values = stationReportAnalysisDAO.selectYesterday(dto);
        Integer totalNum = values.size();
        AtomicReference<Integer> noStandardNum = new AtomicReference<>(0);
        AtomicReference<Double> dayAverageVal = new AtomicReference(0.0);
        int size = values.size();
        if (size > 0) {
            AlarmSetPO alarmSetRedAlarmVO = alarmSetDAO.findByLevelAndTffect(EAlarmLevel.ALARM_RED.getKey(), 1, null);
            values.forEach(item -> {
                dayAverageVal.set(dayAverageVal.get() + item);
                if (1 == dto.getType() && item.compareTo(alarmSetRedAlarmVO.getCod()) >= 0)
                    noStandardNum.getAndSet(noStandardNum.get() + 1);

                if (2 == dto.getType() && item.compareTo(alarmSetRedAlarmVO.getTn()) >= 0)
                    noStandardNum.getAndSet(noStandardNum.get() + 1);

                if (3 == dto.getType()) {
                    int seasonNumber = Calendar.getInstance().get(Calendar.MONTH);
                    Double nh3N = 0.0;
                    if (seasonNumber >= 4 && seasonNumber <= 9) nh3N = alarmSetRedAlarmVO.getNh3NS();
                    else nh3N = alarmSetRedAlarmVO.getNh3NW();
                    if (item.compareTo(nh3N) >= 0) noStandardNum.getAndSet(noStandardNum.get() + 1);
                }

                if (4 == dto.getType() && item.compareTo(alarmSetRedAlarmVO.getTp()) >= 0)
                    noStandardNum.getAndSet(noStandardNum.get() + 1);

                if (7 == dto.getType() && item.compareTo(alarmSetRedAlarmVO.getSs()) >= 0)
                    noStandardNum.getAndSet(noStandardNum.get() + 1);

                if (9 == dto.getType() && (0 <= item.compareTo(alarmSetRedAlarmVO.getPhMax())
                        || !(0 <= item.compareTo(alarmSetRedAlarmVO.getPhMin())))) {
                    noStandardNum.getAndSet(noStandardNum.get() + 1);
                }
            });
        }

        HashMap map = Maps.newHashMap();
//        map.put("totalNum", totalNum);
//        map.put("noStandardNum", noStandardNum);
//        map.put("standardNum", standardNum);
        if (dayAverageVal.get() > 0)
            map.put("dayAverageVal", NumberUtil.precision(new BigDecimal(Double.valueOf(dayAverageVal.get()) / size), 2));
        else map.put("dayAverageVal", null);

        if (totalNum > 0)
            map.put("standardNumThan", NumberUtil.precision(new BigDecimal(Double.valueOf((totalNum - noStandardNum.get())) / totalNum), 2));
        else map.put("standardNumThan", null);
        return map;
    }

    public String operationAllAnalysis(Long stationId, String dataNode) {
        List<StationReportAnalysisPO> values = stationReportAnalysisDAO.selectAllYesterday(stationId, dataNode);
        AtomicReference<Integer> totalNum = new AtomicReference<>(0);
        AtomicReference<Integer> noStandardNum = new AtomicReference<>(0);
        if (values.size() > 0) {
            AlarmSetPO alarmSetRedAlarmVO = alarmSetDAO.findByLevelAndTffect(EAlarmLevel.ALARM_RED.getKey(), 1, dataNode);
            values.stream().forEach(item -> {
                if (null != item.getCod()) {
                    totalNum.getAndSet(totalNum.get() + 1);
                    if (item.getCod().compareTo(alarmSetRedAlarmVO.getCod()) >= 0)
                        noStandardNum.getAndSet(noStandardNum.get() + 1);
                }

                if (null != item.getTn()) {
                    totalNum.getAndSet(totalNum.get() + 1);
                    if (item.getTn().compareTo(alarmSetRedAlarmVO.getTn()) >= 0)
                        noStandardNum.getAndSet(noStandardNum.get() + 1);
                    ;
                }

                int seasonNumber = Calendar.getInstance().get(Calendar.MONTH);
                Double nh3N = 0.0;
                if (seasonNumber >= 4 && seasonNumber <= 9) nh3N = alarmSetRedAlarmVO.getNh3NS();
                else nh3N = alarmSetRedAlarmVO.getNh3NW();
                if (null != item.getNh3n()) {
                    totalNum.getAndSet(totalNum.get() + 1);
                    if (item.getNh3n().compareTo(nh3N) >= 0) noStandardNum.getAndSet(noStandardNum.get() + 1);
                }

                if (null != item.getTp()) {
                    totalNum.getAndSet(totalNum.get() + 1);
                    if (item.getTp().compareTo(alarmSetRedAlarmVO.getTp()) >= 0)
                        noStandardNum.getAndSet(noStandardNum.get() + 1);
                }

                if (null != item.getSs()) {
                    totalNum.getAndSet(totalNum.get() + 1);
                    if (item.getSs().compareTo(alarmSetRedAlarmVO.getSs()) >= 0)
                        noStandardNum.getAndSet(noStandardNum.get() + 1);
                }

                if (null != item.getPh()) {
                    totalNum.getAndSet(totalNum.get() + 1);
                    if ((0 <= item.getPh().compareTo(alarmSetRedAlarmVO.getPhMax())
                            || !(0 <= item.getPh().compareTo(alarmSetRedAlarmVO.getPhMin()))))
                        noStandardNum.getAndSet(noStandardNum.get() + 1);
                }
            });
        }
        Integer db = (totalNum.get() - noStandardNum.get());
        return NumberUtil.precision(new BigDecimal((totalNum.get() > 0 ? db.doubleValue() / totalNum.get() : 0.00) * 100), 0);
    }

    public void selectWaterQualityUp(WaterYieldUpDTO waterYieldUpDTO) {
        stationReportAnalysisDAO.selectWaterQualityUp(waterYieldUpDTO);
    }

    public void selectWaterQualityDe(WaterYieldUpDTO waterYieldUpDTO) {
        stationReportAnalysisDAO.selectWaterQualityDe(waterYieldUpDTO);
    }

    public Map<String, List<ManyDataThresholdVO>> selectManyDataThreshold(StationIdDTO dto) {
        List<ManyDataThresholdVO> list = gatherDevPointDAO.selectManyDataThreshold(dto);
        if (null == list && list.size() <= 0) return Maps.newHashMap();
        return list.stream().collect(Collectors.groupingBy(ManyDataThresholdVO::getProcessunitName));
    }

    public void updateManyDataThreshold(ManyDataThresholdsDTO dto) {
        gatherDevPointDAO.updateManyDataThreshold(dto.getList());
    }

    public Map<String, Object> selectManyData(manyDataAnalysisQueryDTO dto) {
        Map<String, Object> map = Maps.newHashMap();
        List<StationReportAnalysisVO> manyData = stationReportAnalysisDAO.selectManyData(dto);
        List<StationReportAnalysis2VO> dataAvgMaxMin = stationReportAnalysisDAO.selectManyDataAvgMaxMin(dto);
        map.put("manyData", manyData);
        map.put("dataAvgMaxMin", dataAvgMaxMin);
        return map;
    }

    public List<String> selectWaterQualityPoint(StationIdDTO dto) {
        return gatherDevPointDAO.selectWaterQualityPoint(dto);
    }
}
